#ifndef YIGCLIENT_H
#define YIGCLIENT_H

// System includes
#include <QObject>
#include <QThread>

// Local includes
#include "oscpack/ip/IpEndpointName.h"
#include "oscpack/ip/UdpSocket.h"
#include "oscpack/osc/OscOutboundPacketStream.h"
#include "network/yigpacketlistener.h"

class Yig;

class YigClient;

/**
*   YigClientThread
*   QThread subclass that runs our networking in a separate thread
*/
class YigClientThread : public QThread
{
    Q_OBJECT

public:

    /**
    *   YigClientThread constructor QThread subclass that runs our networking in a separate thread
    *   @param YigClient* client Pointer to the parent Yig Client
    *   @param int receivePort Port that the thread listens to/sends on
    */
    YigClientThread(YigClient* client, int receivePort);

    ~YigClientThread();

    /**
    *   run Start this thread
    */
    void run();

    /**
    *   getReceiveSocket
    *   @return UdpReceiveSocket* Returns a pointer to the thread's receive socket
    */
    UdpReceiveSocket* getReceiveSocket();

    /**
    *   send
    *   @param QString address the IP address which to send a message
    *   @param int port the port on which we send our message
    *   @param osc::OutboundPacketStream packet The message, as a packet, that we send
    */
    void send(QString address, int port, osc::OutboundPacketStream packet);

    /**
    *   quitConnection
    *   closes the socket and ends networking
    */
    void quitConnection();

    /**
    *   Returns a pointer to the packet listener. used for Signals/Slots
    *   @return YigPacketListener* The pointer to the listener
    */
    YigPacketListener* getPacketListener();

private:

    /** pointer to the parent client */
    YigClient* mClient;
    /** packet listener used for parsing messages */
    YigPacketListener listener;
    /** the socket this client sends/receives on */
    UdpReceiveSocket* receiveSocket;
    /** synchronizes the out/in port */
    SocketReceiveMultiplexer mux;
};

/**
*   YigClient
*   Maintains persistent local user status with networked data, also handles multithread data access
*/
class YigClient : public QObject
{
    Q_OBJECT

public:

    /**
    *   YigClient Constructor
    *   @param const char *ipAddress to send messages to
    *   @param int receivePort Port to send messages on
    */
    YigClient(const char *ipAddress = "127.0.0.1", int receivePort = 7000, QObject *parent = 0);

    /**
    *   YigClient deconstructor
    */
    ~YigClient();

    /**
    *   send Sends the packet stream to the stored ip address/port number
    *   @param osc::OutboundPacketStream packetStream the message to be sent
    *   @param int sendPort Port to send messages to
    */
    void send(osc::OutboundPacketStream packetStream, int sendPort = 67110);

    /**
    *   send Sends the packet stream to the stored ip address/port number
    *   @pram ip the ip address to send the packet
    *   @param osc::OutboundPacketStream packetStream the message to be sent
    *   @param int sendPort Port to send messages to
    */
    void send(QString ip, osc::OutboundPacketStream packetStream, int sendPort = 67110);

    /** starts the internal thread and begins networking */
    void start();

    /** stops the internal thread and ends networking */
    void stop();

    /**
    *   give this client a pointer to our main Yig instance
    *   @param Yig* yig the pointer to the current Yig instance
    */
    void setYig(Yig* yig);

signals:

public slots:


private:

    /** Yig* yig The main yig that we will communicate with for network parsing */
    Yig* mYig;
    /** ip address this client communicates with */
    QString mIpAddress;
    /** the ports that we send to and receive on */
    int mReceivePort;
    /** The client osc thread that actually sends/receives osc messages */
    YigClientThread* oscThread;
};

#endif // YIGCLIENT_H
